//
// Created by LiuYou on 2021/5/7.
//

#include <cstdio>
#include <cstdlib>
#include <fcntl.h>
#include <unistd.h>
#include <cerrno>

/**
 * @brief 通过MyCopy来实现MyCat
 *
 *
 * @return 0
 */
int main(int argc, char** argv) {
    if (argc < 2) {
        std::fprintf(stderr, "Usage: ...\n");
        std::exit(1);
    }

    // TODO 注意: 对信号造成假错这个问题进行处理
    //  使用到了 do-while 语句。
    int sFD{};
    do {
        sFD = open(argv[1], O_RDONLY);
        if (sFD < 0) {
            if (errno != EINTR) {
                std::perror("open()");
                std::exit(1);
            }

        }
    } while (sFD < 0);

    int dFD{1};
/*    do {
        dFD = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0600);
        if (dFD < 0) {
            if (errno != EINTR) {
                // 防止产生内存泄漏, 因为sFD已经成功打开了。
                close(sFD);
                std::perror("open()");
                std::exit(1);
            }
        }
    } while (dFD < 0);*/

    // 这个程序效率的核心问题在这里 BUF_SIZE的长度, 对这个程序的效率影响非常大！！！！
    const int BUF_SIZE = 1024;
    char buf[BUF_SIZE]{};
    int pos = 0;
    for (;;) {
        // 但是没有必要坚持读够sizeof(buf)个字节, 因为文件本身可能就没有这么多个字节数
        // 所以, 采取的策略是有多少个字节就读多少个字节。
        ssize_t len = read(sFD, buf, sizeof(buf));
        if (len < 0) {
            if (errno == EINTR) {
                continue;
            }
            std::perror("read()");
            break;
        }
        if (len == 0) {
            break;
        }

        // 坚持写够len个字节
        while (len > 0) {
            ssize_t ret = write(dFD, buf + pos, len);
            if (ret < 0) {
                if (errno == EINTR) {
                    continue;
                }
                std::perror("write()");
                // 这里其实是有内存泄漏的。
                std::exit(1);
            }
            // 这里很精妙
            len -= ret;
            pos += ret;
        }
    }


    close(sFD);

    return 0;
}
